/*
 * File:   UserDelay.c
 * Author: Honrun
 */

#include "gd32w51x.h"
#include "stdint.h"
#include "DevicesDelay.h"


/*
 * Return:      void
 * Parameters:  void
 * Description: SysTick初始化
 */
void vSysTickDelayInit(void)
{
    /* Set the SysTick Counter Load */
    SysTick->LOAD = SysTick_LOAD_RELOAD_Msk;
    /* Load the SysTick Counter Value */
    SysTick->VAL = 0;
    /* ENABLE */
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
}

/*
 * Return:      void
 * Parameters:  Time: 延时时间
 * Description: 秒延时
 */
void vSysTickDelayS(float fTime)
{
    vSysTickDelayMs(fTime * 1000.0f);
}

/*
 * Return:      void
 * Parameters:  Time: 延时时间
 * Description: 毫秒延时
 */
void vSysTickDelayMs(float fTime)
{
    int32_t iTime = fTime;

    while((iTime--) > 0)
    {
        vSysTickDelayUs(1000.0f);
    }

    fTime -= iTime;
    vSysTickDelayUs(fTime * 1000.0f);
}

/*
 * Return:      void
 * Parameters:  Time: 延时时间
 * Description: 微秒延时
 */
void vSysTickDelayUs(float fTime)
{
    uint32_t uiTimeStop = 0u, uiTimeStart = 0;

    if(fTime < 0.1f)
        return;

    uiTimeStart = (SysTick_LOAD_RELOAD_Msk - SysTick->VAL);
    uiTimeStop  = (uint32_t)((SystemCoreClock / 1000000u) * fTime + uiTimeStart);
    /* 24bit溢出处理 */
    uiTimeStop &= SysTick_LOAD_RELOAD_Msk;

    if(uiTimeStop >= uiTimeStart)
        while(((SysTick_LOAD_RELOAD_Msk - SysTick->VAL) > uiTimeStart) && ((SysTick_LOAD_RELOAD_Msk - SysTick->VAL) < uiTimeStop));
    else
        while(!(((SysTick_LOAD_RELOAD_Msk - SysTick->VAL) > uiTimeStop) && ((SysTick_LOAD_RELOAD_Msk - SysTick->VAL) < uiTimeStart)));
}

/*
 * Return:      void
 * Parameters:  void
 * Description: DWT初始化
 */
void vDWTDelayInit(void)
{
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CYCCNT = 0;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}

/*
 * Return:      void
 * Parameters:  Time: 延时时间
 * Description: 秒延时
 */
void vDWTDelayS(float fTime)
{
    int32_t iTime = fTime;

    while((iTime--) > 0)
    {
        vDWTDelayUs(1000000.0f);
    }

    fTime -= iTime;
    vDWTDelayUs(fTime * 1000000.0f);
}

/*
 * Return:      void
 * Parameters:  Time: 延时时间
 * Description: 毫秒延时
 */
void vDWTDelayMs(float fTime)
{
    vDWTDelayUs(fTime * 1000.0f);
}

/*
 * Return:      void
 * Parameters:  Time: 延时时间
 * Description: 微秒延时
 */
void vDWTDelayUs(float fTime)
{
    uint32_t uiTimeStop = 0u, uiTimeStart = 0;

    if(fTime < 0.1f)
        return;

    uiTimeStart = DWT->CYCCNT;
    uiTimeStop  = (uint32_t)((SystemCoreClock / 1000000u) * fTime) + uiTimeStart;

    if(uiTimeStop >= uiTimeStart)
        while((DWT->CYCCNT > uiTimeStart) && (DWT->CYCCNT < uiTimeStop));
    else
        while(!((DWT->CYCCNT > uiTimeStop) && (DWT->CYCCNT < uiTimeStart)));
}
